#ifndef MODEL_H
#define MODEL_H

#include <QtCore>

#include "../filehandling/FileType.h"

// semafory
#include "../network/monitor.h"

#include "Job.h"
#include "Utils.h"

namespace Client {

/**
 * @brief Informacja o udostępnianym pliku.
 **/
struct SharedFileDesc {
	/// nazwa pliku
	QString fname;

	/// położenie pliku (np. /home/user/shared_folder/)
	QString path;

	/// suma kontrolna
	QByteArray hash;

	/// rozmiar
	int size;

	/// typ pliku
	Common::FileType type;
};

/**
 * Model danych przedstawiający listę udostępnianych plików.
 * Wykorzystywany jako źródło dla widoku plików.
 **/
class SharedFilesModel : public QAbstractItemModel {
	Q_OBJECT

public:
	/**
	 * Konstruktor.
	 *
	 * @param ref referencja na obserwowaną listę plików
	 **/
	SharedFilesModel(QList<SharedFileDesc*> & ref, QObject * parent = 0);

	/**
	 * Ilość plików
	 **/
	int rowCount(const QModelIndex & parent = QModelIndex()) const;

	/**
	 * Ilośc kolumn
	 **/
	int columnCount(const QModelIndex & parent = QModelIndex()) const;

	/**
	 * Dane związane z konkretnym plikiem wskazywanym przez index
	 **/
	QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

	/**
	 * Indeks
	 **/
	QModelIndex index(int row, int column, const QModelIndex &parent) const;

	QModelIndex parent(const QModelIndex &index) const;

	Qt::ItemFlags flags(const QModelIndex &index) const;
	QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

private:
	/// referencja na spis udostępnianych plików
	QList<SharedFileDesc*> & shared_;
};

/**
 * Model danych przedstawiający listę zadań
 **/
class JobsModel : public QAbstractItemModel {
	Q_OBJECT

public:
	/**
	 * Konstruktor.
	 *
	 * @param ref referencja na obserwowaną listę plików
	 **/
	JobsModel(QList<Job*> & ref, QObject * parent = 0);

	/**
	 * Ilość plików
	 **/
	int rowCount(const QModelIndex & parent = QModelIndex()) const;

	/**
	 * Ilośc kolumn
	 **/
	int columnCount(const QModelIndex & parent = QModelIndex()) const;

	/**
	 * Dane związane z konkretnym plikiem wskazywanym przez index
	 **/
	QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;

	/**
	 * Indeks
	 **/
	QModelIndex index(int row, int column, const QModelIndex &parent) const;

	QModelIndex parent(const QModelIndex &index) const;

	Qt::ItemFlags flags(const QModelIndex &index) const;
	QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

private:
	/// referencja na spis udostępnianych plików
	QList<Job*> & jobs_;
};

/**
 * @brief Główny moduł serwera odpowiedzialny za cała jego funkcjonalność.
 *
 * Przechowuje informacje o aktualnie pobieranych plikach, składa w całość części
 * pobranych plików, a także dokonuje (na żądanie kontrolera) podziału wysyłanych plików
 * na fragmenty. Jest też odpowiedzialny za przechowywanie informacji o udostępnianych plikach.
 *
 **/
class Model
{
public:
	/**
	 * Konstruktor.
	 **/
	Model();

	/**
	 * Destruktor.
	 **/
	~Model();

	/**
	 * @return identyfikator klienta
	 **/
	int id() {
		return client_id;
	}

	/**
	 * @param id_ nowy identyfikator klienta
	 **/
	void id(int id_) {
		client_id = id_;
	}

	/**
         * Wymuszenie zapisania wszystkich danych
	 **/
	void saveAll();

	/**
	 * Zwróć fragment pliku określonego przez sume kontrolną i jego wielkość.
	 *
	 * @param hash suma kontrolna pliku
	 * @param size rozmiar pliku
	 * @param chunk numer żądanego fragmentu
	 *
	 * @return żądany fragment, w przypadku błędu zwracany kontener jest pusty
	 **/
	QByteArray getChunk(QByteArray hash, int size, int chunk);

	/**
	 * Dopisz do ściąganego pliku pobrany fragment.
	 *
	 * @param hash suma kontrolna ściąganego pliku
	 * @param size rozmiar pliku
	 * @param chunk numer fragmentu
	 * @param chunk_data dane fragmentu
	 *
	 * @return true w przypadku, gdy operacja się powiodła
	 **/
	bool setChunk(QByteArray hash, int size, int chunk, QByteArray chunk_data, int seed_id);

	/**
	 * Zwalnia danego seeda dla podanego zadania (związane np. z błędnym pakietem)
	 **/
	void freeSeed(QByteArray hash, int size, int client_id);

	/**
	 * Dodaj nowe zadanie
	 **/
	void addJob(QString fname, QByteArray hash, int size, Common::FileType type);

	/**
	 * @return lista wszystkich zadań (aktywnych oraz zatrzymanych)
	 **/
	QList<Job*> & jobs();

	/**
	 * Dodaj nowy udostępniany plik. Wszystkie parametry pliku są ustawiane automatycznie
	 * (typ na podstawie rozszerzenia) oraz liczona jest suma kontrolna.
	 *
	 * @param path pełna ścieżka do pliku
	 *
	 * @return wskaźnik na wypełnioną strukturę opisującą dodany plik
	 **/
	SharedFileDesc * addSharedFile(QString path);

	/**
	 * @return lista udostępnianych plików
	 **/
	QList<SharedFileDesc*> & shared();

private:
	/// lista wszystkich zadań pobierania i udostępniania plików
	QList<Job*> jobs_;

	/// lista wszystkich udostępnianych plików
	QList<SharedFileDesc *> shared_;

	/// identyfikator użytkownika, nadawany przez serwer
	/// dla niezarejestrowanego użytkownika jest zerem
	int client_id;

	/// mutex synchronizujący operacje odczytu z dysku
	Semaphore mutex;
};

} // namespace Client

#endif // MODEL_H
